#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <pthread.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>

#include "proto.h"

struct recv_msg_st {
    struct msg_st msg;
    struct sockaddr_in client_addr;
};

void *handle_request(void *arg);

int main(void)
{
    struct sockaddr_in localaddr, readaddr;
    socklen_t raddr_len;
    struct recv_msg_st *rcv_data; // 接收的数据
    int ret;
    pthread_t tid;
    int udp_socket = socket(AF_INET, SOCK_DGRAM, 0); // 创建 udp socket

    if (-1 == udp_socket) {
        perror("socket()");
        return 1;
    }

    localaddr.sin_family = AF_INET;
    inet_aton(RCVADDR, &localaddr.sin_addr); // 点分十进制地址转整形
    localaddr.sin_port = htons(PORT); // 端口本地字节序转网络字节序

    if (-1 == bind(udp_socket, (struct sockaddr *)&localaddr, sizeof(localaddr))) {
        perror("bind()");
        close(udp_socket);
        return 1;
    }

    printf("UDP server 监听 %s:%d\n", RCVADDR, PORT);

    while (1) {
        // 接收数据
        rcv_data = malloc(sizeof(struct recv_msg_st));
        if (NULL == rcv_data) {
            perror("malloc()");
            continue;
        }

        raddr_len = sizeof(struct sockaddr_in); // 初始化长度
        ret = recvfrom(udp_socket, &rcv_data->msg, sizeof(struct msg_st),\
                0, (struct sockaddr *)&readaddr, &raddr_len);

        if (-1 == ret) {
            perror("recvfrom()");
            free(rcv_data);
            continue;
        }

        // 保存客户端地址
        rcv_data->client_addr = readaddr;

        // 调试语句
        printf("from ip:%s, from port:%d\n", inet_ntoa(readaddr.sin_addr), ntohs(readaddr.sin_port));
        printf("id:%d, path:%s\n", rcv_data->msg.id, rcv_data->msg.name);

        // 创建线程处理请求
        if (pthread_create(&tid, NULL, handle_request, rcv_data) != 0) {
            perror("pthread_create()");
            free(rcv_data);
        }

        // 分离线程，避免资源泄漏
        pthread_detach(tid);
    }

    close(udp_socket);

    return 0;
}


// 线程处理函数
void *handle_request(void *arg) 
{
    struct recv_msg_st *rcv_data = (struct recv_msg_st *)arg;
    struct stat file_stat;
    int fd;
    ssize_t bytes_read;
    char response[BUFSIZE] = {0};
    int udp_socket;
    struct sockaddr_in client_addr;
    ssize_t sent_bytes;
    socklen_t client_addr_len;

    // 检查路径是否以 "/tmp" 开头
    if (strncmp(rcv_data->msg.name, "/tmp", 4) != 0) {
        strncpy(response, "不合法路径", NAMESIZE);
    } else {
        // 检查文件是否存在
        if (-1 == stat(rcv_data->msg.name, &file_stat)) {
            strncpy(response, "no file", NAMESIZE);
        } else {
            // 返回文件路径
            strncpy(response, rcv_data->msg.name, NAMESIZE);

            // 打开文件并读取内容
            fd = open(rcv_data->msg.name, O_RDONLY);
            if (-1 == fd) {
                strncpy(response, "无法打开文件", BUFSIZE);
            } else {
                bytes_read = read(fd, response, BUFSIZE - 1);
                if (-1 == bytes_read) {
                    strncpy(response, "读取文件失败", BUFSIZE);
                } else {
                    response[bytes_read] = '\0'; // 确保字符串以 null 结尾
                }
                close(fd);
            }
        }
    }

    // 打印调试信息
    printf("请求 ID: %d, Path: %s, 响应: %s\n", rcv_data->msg.id, rcv_data->msg.name, response);


    // 创建 UDP socket 用于发送响应
    udp_socket = socket(AF_INET, SOCK_DGRAM, 0);
    if (-1 == udp_socket) {
        perror("socket()");
        free(rcv_data);
        return NULL;
    }

    // 发送响应到客户端
    client_addr = rcv_data->client_addr;
    client_addr_len = sizeof(client_addr);
    sent_bytes = sendto(udp_socket, response, strlen(response), 0, \
            (struct sockaddr *)&client_addr, client_addr_len);
    if (-1 == sent_bytes) {
        perror("sendto()");
    }

    printf("已发送数据：%s\n", response);

    // 关闭 socket 并释放内存
    close(udp_socket);

    // 释放动态分配的内存
    free(rcv_data);

    return NULL;
}

